﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using System.Collections.Concurrent;
using System.Threading;

namespace RAP.Framework.Libary.Utils
{
	/// <summary>
	/// 文件监视工具对象
	/// </summary>
	public class FileSystemWatcherUtils
	{
		#region 常量
		/// <summary>
		/// 文件或文件夹变化时的回调函数
		/// </summary>
		public const string CALL_BACK_FIELD = "Callback";

		/// <summary>
		/// 监视器对象的字段名称
		/// </summary>
		public const string WATCHER_FIELD = "Watcher";

		/// <summary>
		/// 监视路径的字段名称
		/// </summary>
		public const string PATH_FIELD = "Path";

		/// <summary>
		/// 文件过滤参数的字段名称
		/// </summary>
		public const string FILTER_FIELD = "Filter";

		/// <summary>
		/// LastRaisingPath
		/// </summary>
		public const string LAST_RAISING_PATH_FIELD = "LastRaisingPATH";

		/// <summary>
		/// MinRaisingDuration
		/// </summary>
		public const string MIN_RAISING_DURATION_FIELD = "MinRaisingDuration";

		/// <summary>
		/// IsRaisingEvent
		/// </summary>
		public const string IS_RAISING_EVENT = "IsRaisingEvent";

		/// <summary>
		/// 文件变更事件触发的最小间隔事件
		/// </summary>
		public const int MIN_RAISING_DURATION = 2000;
		#endregion

		/// <summary>
		/// 
		/// </summary>
		protected static IDictionary _fileSystemWatchers = new ConcurrentDictionary<object, IDictionary> ( );

		/// <summary>
		/// 
		/// </summary>
		protected static Action<object, FileSystemEventArgs> _onChangedHandler;

		/// <summary>
		/// 当被监视的文件或文件夹发生变化时的事件
		/// </summary>
		public static Action<object, FileSystemEventArgs> OnChangedHandler
		{
			get
			{
				if ( _onChangedHandler == null )
				{
					_onChangedHandler = ( object sender, FileSystemEventArgs e ) =>
					{
						IDictionary watcherInfo = _fileSystemWatchers[ sender ] as IDictionary;
						if ( watcherInfo != null )
						{
							//检测当前路径是否在指定的时间内重复触发
							IDictionary lastRaisingFile = watcherInfo.ToDictionary ( FileSystemWatcherUtils.LAST_RAISING_PATH_FIELD );
							DateTime? lastRaisingTime = lastRaisingFile.ToDateTime ( e.FullPath );
							int minRaisingDuration = watcherInfo.ToInt32 ( FileSystemWatcherUtils.MIN_RAISING_DURATION_FIELD, FileSystemWatcherUtils.MIN_RAISING_DURATION );
							if ( lastRaisingTime != null )
							{
								TimeSpan ts = DateTime.Now.Subtract ( lastRaisingTime.Value );
								if ( ts.TotalMilliseconds < minRaisingDuration )
								{
									return;
								}
							}
							lastRaisingFile[ e.FullPath ] = DateTime.Now;
							Action<IDictionary, FileSystemEventArgs> callBack = watcherInfo[ CALL_BACK_FIELD ] as Action<IDictionary, FileSystemEventArgs>;
							if ( callBack != null )
							{
								if ( lastRaisingFile.ToBoolean ( IS_RAISING_EVENT ) )
								{
									return;
								}
								lastRaisingFile[ IS_RAISING_EVENT ] = true;
								( new Thread ( new ThreadStart ( ( ) =>
								{
									Thread.Sleep ( minRaisingDuration / 2 );
									try
									{
										callBack ( watcherInfo, e );
									}
									finally
									{
										lastRaisingFile[ IS_RAISING_EVENT ] = false;
									}
								} ) ) ).Start ( );
							}
						}
					};
				}
				return _onChangedHandler;
			}
			set
			{
				_onChangedHandler = value;
			}
		}

		/// <summary>
		/// 注册一个监视
		/// </summary>
		/// <param name="path"></param>
		/// <param name="filter"></param>
		/// <param name="notifyFilters"></param>
		/// <param name="onChangedCallBack"></param>
		/// <returns></returns>
		public static IDictionary RegisterWatcher ( string path, string filter, NotifyFilters notifyFilters, Action<IDictionary, FileSystemEventArgs> onChangedCallBack, bool includeSubdirectories = true )
		{
			IDictionary watcherInfo = new Hashtable ( );
			FileSystemWatcher watcher = new FileSystemWatcher ( path, filter );
			watcher.EnableRaisingEvents = true;
			watcher.NotifyFilter = notifyFilters;
			watcher.IncludeSubdirectories = includeSubdirectories;
            watcher.Changed += new FileSystemEventHandler ( FileSystemWatcherUtils.OnChangedHandler );
			watcher.Created += new FileSystemEventHandler ( FileSystemWatcherUtils.OnChangedHandler );
			watcher.Deleted += new FileSystemEventHandler ( FileSystemWatcherUtils.OnChangedHandler );
			watcherInfo[ FileSystemWatcherUtils.LAST_RAISING_PATH_FIELD ] = new Hashtable ( );
			watcherInfo[ FileSystemWatcherUtils.CALL_BACK_FIELD ] = onChangedCallBack;
			watcherInfo[ FileSystemWatcherUtils.WATCHER_FIELD ] = watcher;
			watcherInfo[ FileSystemWatcherUtils.PATH_FIELD ] = path;
			watcherInfo[ FileSystemWatcherUtils.FILTER_FIELD ] = filter;
			_fileSystemWatchers[ watcher ] = watcherInfo;
			return watcherInfo;
		}

		/// <summary>
		/// 注销监视
		/// </summary>
		/// <param name="watcherInfo"></param>
		public static void UnRegisterWatcher ( IDictionary watcherInfo )
		{
			FileSystemWatcher watcher = watcherInfo.ToObject<FileSystemWatcher> ( WATCHER_FIELD );
			FileSystemWatcherUtils.UnRegisterWatcher ( watcher );
		}

		/// <summary>
		/// 注销监视
		/// </summary>
		/// <param name="watcher"></param>
		public static void UnRegisterWatcher ( FileSystemWatcher watcher )
		{
			if ( watcher != null )
			{
				watcher.Changed -= new FileSystemEventHandler ( FileSystemWatcherUtils.OnChangedHandler );
				watcher.Created -= new FileSystemEventHandler ( FileSystemWatcherUtils.OnChangedHandler );
				watcher.Deleted -= new FileSystemEventHandler ( FileSystemWatcherUtils.OnChangedHandler );
				watcher.Dispose ( );
				_fileSystemWatchers.Remove ( watcher );
			}
		}

		/// <summary>
		/// 释放所有监视器
		/// </summary>
		public static void Dispose ( )
		{
			if ( _fileSystemWatchers != null )
			{
				lock ( typeof ( FileSystemWatcherUtils ) )
				{
					if ( _fileSystemWatchers != null )
					{
						foreach ( FileSystemWatcher watcher in _fileSystemWatchers.Keys )
						{
							FileSystemWatcherUtils.UnRegisterWatcher ( watcher );
						}
					}
				}
			}
		}
	}
}
